﻿package com.bizmlib.utils
{
	import flash.display.DisplayObject;
	import flash.display.Stage;
	import flash.events.Event;
	import flash.events.MouseEvent;
	
	
	public class StageMouseEventSubscriber
	{
		public static const MOUSE_MOVE:uint = 1;
		public static const MOUSE_WHEEL:uint = 2;
		
		protected static const CHECK_PHASE_SUBSCRIBE:int = 10;
		protected static const CHECK_PHASE_UNSUBSCRIBE:int = 20;
		
		private static var views:Array;
		
		
		public static function takeCareOf(view:DisplayObject, options:uint = 0):void
		{
			//trace(toString() + ".takeCareOf(" + arguments + ")");
			
			checkViewsList();
			
			var viewCasted:IStageMouseEventSubscribable = view as IStageMouseEventSubscribable;
			if(!viewCasted)
				return;
			
			var itemData:ListItemData = findItemData(view);
			var doesExist:Boolean = false;
			if(itemData)
			{
				doesExist = true;
				removeStageEventListeners(itemData);
				itemData.options = options;
			}
			else
			{
				itemData = new ListItemData(view, options);
				views.push(itemData);
			}
			
			checkViewSubscription(view);
		}
		public static function leaveOut(view:DisplayObject):void
		{
			checkViewsList();
			
			var viewCasted:IStageMouseEventSubscribable = view as IStageMouseEventSubscribable;
			if(!viewCasted)
				return;
			
			var itemData:ListItemData = findItemData(view, true);
			
			if(itemData)
			{
				removeStageEventListeners(itemData);
				view.removeEventListener(Event.ADDED_TO_STAGE, handleViewAddedToStageEvent);
				view.removeEventListener(Event.REMOVED_FROM_STAGE, handleViewRemovedFromStageEvent);
				itemData.view = null;
			}
		}
		public static function findItemData(view:DisplayObject, removeIfFound:Boolean = false):ListItemData
		{
			if(!views)
				return null;
			
			var itemData:ListItemData;
			for(var i:int=0; i<views.length; i++)
			{
				if((views[i] as ListItemData).view==view)
				{
					itemData = views[i] as ListItemData;
					if(removeIfFound)
						views.splice(i, 1);
					break;
				}
			}
			
			return itemData;
		}
		
		
		private static function checkViewsList():void
		{
			if(!views)
				views = new Array();
		}
		
		private static function checkViewSubscription(view:DisplayObject, checkPhase:int = 0):void
		{
			//trace(toString() + ".checkViewSubscription(" + arguments + ")");
			
			var itemData:ListItemData = findItemData(view);
			checkPhase = checkPhase || CHECK_PHASE_SUBSCRIBE;
			
			if(!view.stage || checkPhase==CHECK_PHASE_UNSUBSCRIBE)
			{
				//trace("unsubscribing " + view);
				view.removeEventListener(Event.REMOVED_FROM_STAGE, handleViewRemovedFromStageEvent);
				view.addEventListener(Event.ADDED_TO_STAGE, handleViewAddedToStageEvent);
				removeStageEventListeners(itemData);
			}
			else
			{
				//trace("subscribing " + view);
				
				view.removeEventListener(Event.ADDED_TO_STAGE, handleViewAddedToStageEvent);
				view.addEventListener(Event.REMOVED_FROM_STAGE, handleViewRemovedFromStageEvent);
				addStageEventListeners(itemData);
			}
		}
		
		private static function removeStageEventListeners(itemData:ListItemData):void
		{
			var view:DisplayObject = itemData.view;
			var stage:Stage = view.stage;
			if(!stage)
				return;
			
			var viewCasted:IStageMouseEventSubscribable = view as IStageMouseEventSubscribable;
			stage.removeEventListener(MouseEvent.MOUSE_MOVE, viewCasted.handleStageMouseMoveEvent);
			stage.removeEventListener(MouseEvent.MOUSE_WHEEL, viewCasted.handleStageMouseWheelEvent);
		}
		private static function addStageEventListeners(itemData:ListItemData):void
		{
			var view:DisplayObject = itemData.view;
			var stage:Stage = view.stage;
			if(!stage)
				return;
			var options:int = itemData.options;
			
			var viewCasted:IStageMouseEventSubscribable = view as IStageMouseEventSubscribable;
			if(options & MOUSE_MOVE)
				stage.addEventListener(MouseEvent.MOUSE_MOVE, viewCasted.handleStageMouseMoveEvent, false, 0, true);
			if(options & MOUSE_WHEEL)
				stage.addEventListener(MouseEvent.MOUSE_WHEEL, viewCasted.handleStageMouseWheelEvent, false, 0, true);
		}
		
		private static function handleViewAddedToStageEvent(event:Event):void
		{
			checkViewSubscription(event.target as DisplayObject);
		}
		private static function handleViewRemovedFromStageEvent(event:Event):void
		{
			//trace(toString() + ".handleViewRemovedFromStageEvent(" + arguments + ")");
			
			var view:DisplayObject = event.target as DisplayObject;
			checkViewSubscription(view, CHECK_PHASE_UNSUBSCRIBE);
		}
		
		
		public static function toString():String
		{
			return "[StageMouseEventSubscriber 0.2.0]";
		}
	}
}


import flash.display.DisplayObject;


class ListItemData
{
	public var view:DisplayObject;
	public var options:int;
	
	
	public function ListItemData(view:DisplayObject, options:int)
	{
		this.view = view;
		this.options = options;
	}
}